import { _decorator, Asset, AssetManager, assetManager, Component, director, DirectorEvent, game, Node, sys } from 'cc';
const { ccclass, property } = _decorator;

type BundleContext = {
    ref: AssetManager.Bundle;
    assets: Map<string, Asset>;
    refCount: number;
};

export class AssetsManager {
    private _bundles = new Map<string, BundleContext>();
    private _assetRefs = new Map<string, number>(); // 格式 bundle:path -> count


    private static _instance:AssetsManager;
    public static get instance():AssetsManager {
        if (this._instance == null) {
            this._instance = new AssetsManager();
        }
        return this._instance;
    }


    
    private constructor() {
        director.on(DirectorEvent.BEFORE_SCENE_LAUNCH, this._onSceneChange.bind(this));
    }


    /****************** 核心接口 ******************/
    public async load<T extends Asset>(
        bundleName: string,
        assetPath: string,
        assetType: new () => T
    ): Promise<T> {
        const bundle = await this._getBundle(bundleName);
        const assetKey = this._getAssetKey(bundleName, assetPath);

        // 已有缓存
        if (bundle.assets.has(assetPath)) {
            this._updateRefCount(assetKey, 1);
            return bundle.assets.get(assetPath) as T;
        }

        // 加载新资源
        return new Promise<T>((resolve, reject) => {
            bundle.ref.load(assetPath, assetType, (err, asset) => {
                if (err) {
                    console.error(`[Bundle] Load failed: ${bundleName}/${assetPath}`, err);
                    return reject(err);
                }

                bundle.assets.set(assetPath, asset);
                this._updateRefCount(assetKey, 1);
                resolve(asset as T);
            });
        });
    }

    public release(bundleName: string, assetPath: string): void {
        const assetKey = this._getAssetKey(bundleName, assetPath);
        const currentCount = this._assetRefs.get(assetKey) || 0;

        if (currentCount <= 1) {
            this._destroyAsset(bundleName, assetPath);
        } else {
            this._updateRefCount(assetKey, -1);
        }
    }

    /****************** 新增预热接口 ******************/
    /**
     * 预加载分包（仅加载分包元数据，不加载资源）
     * @param bundleName 分包名称
     * @param background 是否后台静默加载（不阻塞主线程）
     */
    public async preloadBundle(bundleName: string, background = false): Promise<void> {
        if (this._bundles.has(bundleName)) {
            return; // 已加载则直接返回
        }

        if (background) {
            // 后台静默加载（不阻塞主线程）
            this._loadBundle(bundleName).then(bundle => {
                this._bundles.set(bundleName, { 
                    ...bundle,
                    refCount: 0 // 预加载不增加引用计数
                });
            }).catch(err => {
                console.warn(`[Bundle] Background preload failed: ${bundleName}`, err);
            });
            return;
        }

        // 常规预加载（阻塞式）
        try {
            const bundle = await this._loadBundle(bundleName);
            this._bundles.set(bundleName, {
                ...bundle,
                refCount: 0
            });
        } catch (err) {
            console.error(`[Bundle] Preload failed: ${bundleName}`, err);
            throw err;
        }
    }


    /****************** 内存管理 ******************/
    public forceGC(): void {
        this._bundles.forEach((bundle, name) => {
            if (bundle.refCount <= 0 && bundle.assets.size === 0) {
                this._unloadBundle(name);
            }
        });
    }

    /****************** 私有方法 ******************/
    private async _getBundle(bundleName: string): Promise<BundleContext> {
        let bundle = this._bundles.get(bundleName);
        if (!bundle) {
            bundle = await this._loadBundle(bundleName);
            this._bundles.set(bundleName, bundle);
        }
        bundle.refCount++;
        return bundle;
    }

    private async _loadBundle(bundleName: string): Promise<BundleContext> {
        return new Promise((resolve, reject) => {
            assetManager.loadBundle(bundleName, (err, bundle) => {
                if (err) return reject(err);
                resolve({
                    ref: bundle,
                    assets: new Map(),
                    refCount: 0
                });
            });
        });
    }

    private _destroyAsset(bundleName: string, assetPath: string): void {
        const bundle = this._bundles.get(bundleName);
        if (!bundle) return;

        const asset = bundle.assets.get(assetPath);
        if (asset) {
            assetManager.releaseAsset(asset);
            bundle.assets.delete(assetPath);
            this._assetRefs.delete(this._getAssetKey(bundleName, assetPath));
        }

        // 自动卸载空分包
        if (bundle.assets.size === 0 && bundle.refCount <= 0) {
            this._unloadBundle(bundleName);
        }
    }

    private _unloadBundle(bundleName: string): void {
        const bundle = this._bundles.get(bundleName);
        if (!bundle) return;

        bundle.assets.forEach(asset => assetManager.releaseAsset(asset));
        assetManager.removeBundle(bundle.ref);
        this._bundles.delete(bundleName);
    }

    private _updateRefCount(assetKey: string, delta: number): void {
        const count = (this._assetRefs.get(assetKey) || 0) + delta;
        if (count <= 0) {
            this._assetRefs.delete(assetKey);
        } else {
            this._assetRefs.set(assetKey, count);
        }
    }

    private _getAssetKey(bundleName: string, assetPath: string): string {
        return `${bundleName}::${assetPath}`;
    }

    private _onSceneChange(): void {
        // 场景切换时释放所有非保留引用
        this.forceGC();
    }
    
}
    



